#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
#include "log.hpp"
#include <mutex>
#include "cppjieba/Jieba.hpp"

namespace ns_util
{
    class FileUtil{
        public:
            static bool ReadFile(const std::string& file, std::string *out)
            {
                std::ifstream in(file, std::ios::in | std::ios::binary);
                if(!in.is_open()){
                    LOG(FATAL, file + "open false!");
                    return false;
                }
                std::string line;
                while(getline(in, line))
                    (*out) += line;
                return true;
            }
    };

    class StringUtil{
        public:
            static void Split(const std::string& target, std::vector<std::string>* out, const std::string& sep)
            {
                boost::split(*out, target, boost::is_any_of(sep), boost::token_compress_on);
            }
    };

    const char* const DICT_PATH = "./dict/jieba.dict.utf8";
    const char* const HMM_PATH = "./dict/hmm_model.utf8";
    const char* const USER_DICT_PATH = "./dict/user.dict.utf8";
    const char* const IDF_PATH = "./dict/idf.utf8";
    const char* const STOP_WORD_PATH = "./dict/stop_words.utf8";

    class JiebaUtil{
        private:
            static JiebaUtil* instance;
            static std::mutex mtx;
            cppjieba::Jieba jieba;

        private:
            JiebaUtil():jieba(DICT_PATH, HMM_PATH, USER_DICT_PATH, IDF_PATH, STOP_WORD_PATH)
            {}
            JiebaUtil(const JiebaUtil&) = delete;
        public:
            static JiebaUtil* GetInstance()
            {
                if(instance == nullptr)
                {
                    mtx.lock();
                    if(instance == nullptr)
                    {
                        instance = new JiebaUtil();
                        instance->InitJiebaUtil();
                    }
                    mtx.unlock();
                }
                return instance;
            }

            void InitJiebaUtil()
            {}

            void CutStringHelper(const std::string &src, std::vector<std::string> *out)
            {
                jieba.CutForSearch(src, *out);
            }  

        public:
            static void CutString(const std::string &src, std::vector<std::string> *out)
            {
                ns_util::JiebaUtil::GetInstance()->CutStringHelper(src, out);
            }
    };
    JiebaUtil* JiebaUtil::instance = nullptr;
    std::mutex JiebaUtil::mtx;
};